//(app.ino) #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <StreamString.h> #include "app.h" // WiFi SSID パスワード設定(自分の環境に合わせて設定 const char ssid[] = "your-WifiRouter -SSID"; // SSID //使用するWifiルータ のSSID const char password[] = "your-WifiRouter-password"; // password //使用するWifiルータ のパスワード // サーバー設定ポート80で接続 WebServer server(80); int PlayMode = 1; //1:演奏 2:一時停止 int SkipMode = 0; //0:スキップなし 1:スキップ実行 int GpPwm = 28; //PWM出力 GPIO番号 //ピン番号:34 int GpLedRed = 0; //LED赤 GPIO番号 //ピン番号:1 int GpLedGreen = 1; //LED緑 GPIO番号 //ピン番号:2 int GpPlayPauseSw = 2; //Play/Pause SW  //ピン番号:4 int GpPlaySkipSw = 3; //Skip SW  //ピン番号:5 int VOLUME_PIN = 27; //可変抵抗器AD入力 //ピン番号: 32 int ix; //音符の発音時間、無音時間のモード uint64_t interval_T; //[μsec] //LED ON時間、LEDのOFF時間 //interval_T=5msec/実測=6msec, 2msec/3.2msec, 1mse/2msec, 500μsec/1.7msec, 200μsec/1.5msec, 100μ/1.25msec uint64_t current_T; //現在時刻 //pico起動後の経過時間[μsec] uint64_t target_T; //LED状態遷移時刻 int SwCount_PauseSw; //PauseSWのスイッチ接触検出数 int SwCount_SkipSw; //SkipSWのスイッチ接触検出数 int MelodyMode = 0; int TouchSkipSW = 0; int AdValue12; typedef enum //音符解読ステート { SET_SOUND_FREQUENCY_TIME, CHECK_SOUNDING_TIME, STOP_SOUNDING, CHECH_SHORT_SILENT_TIME, STOP_SHORT_SILENT_TIME, CHECK_SILENT_TIME } STATES; STATES states; //Android ブラウザ画面 表示 StreamString html = R"( <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>PWM Melody Producer by Pico W, with Android-type WiFi remote controller </title> <style> h1 { margin: 0; /* 余白をなくす */ padding: 0; /* 余白をなくす */ } h2 { margin: 0; /* 余白をなくす */ padding: 0; /* 余白をなくす */ } h3 { margin: 0; /* 余白をなくす */ padding: 0; /* 余白をなくす */ } span { display: inline-block; } .top_block { margin-top:50px; margin-left:50px; } .buttonA { /* ボタン諸元: Play/Pause */ display: block; width: 200px; font-size: 32px; font-weight: bold; background: #c8eac3; color: #000; padding: 10px; box-sizing: border-box; text-align: center; text-decoration: none; border-radius: 30px; } .buttonA:active { background: #1a720d; color: #FFF; } .Label { /* ラベル諸元:運転中、一時停止 */ display: flex; /*フレックスボックス指定*/ justify-content: center; /*子要素を水平方向中央に配置*/ align-items: center; /*子要素を垂直方向中央に配置*/ width: 150px; height: 50px; border-radius: 5px; /*角の丸み*/ color: red; /*文字色*/ font-size: 24px; font-weight: bold; background: yellow; /*背景色*/ border: solid 2px blue; /*囲み線幅*/ } .text_Label { /*上記ラベルのテキスト部諸元*/ width: 100px; text-align: center; /*文字列中心を中央に配置*/ /*background: skyblue; テキスト部の背景色設定*/ } .TimeStampFont{ /*タイムスタンプフォント関係諸元*/ display: inline-block; color: red; background-color: yellow; font-size: 20px; border-style: solid; border-width: 2px; border-color: lightgreen; padding: 3px; margin: 0; /* 余白をなくす */ } /* ---メロディ進捗:プログレスバーの設定 ---*/ progress[value] { appearance: none; width: 380px; height: 35px; border-radius: 5px; border: 2px solid rgb(0, 0, 0); margin: 0; /* 余白をなくす */ padding: 0; /* 余白をなくす */ } /* ---プログレスバーの背景色(灰色部分)を黄色に設定 --- プログレスバーの灰色部分の色を黄色に変更するには、::-webkit-progress-bar 擬似要素を使って、プログレスバーのバックグラウンドカラーを設定する必要があります。*/ progress[value]::-webkit-progress-bar { background-color: yellow; } /* ---プログレスバーの進行中の部分の色を緑に設定 --- ::-webkit-progress-value 擬似要素で進行中のバーの色を設定します。 */ progress[value]::-webkit-progress-value { background-color: green; } /* --- Firefox用の設定(必要に応じて)--- */ progress[value]::-moz-progress-bar { background-color: green; } /* 電圧入力Volume:プログレスバーのスタイル */ progress.prog2[value] { appearance: none; width: 300px; /* 幅を変更 */ height: 20px; /* 高さを変更 */ border-radius: 10px; /* 角を丸く */ border: 2px solid rgb(0, 0, 0); margin: 0; /* 余白をなくす */ padding: 0; /* 余白をなくす */ } progress.prog2[value]::-webkit-progress-bar { background-color: white; /* 背景色を変更 */ border-radius: 10px; /* 角を丸く //必須 */ } progress.prog2[value]::-webkit-progress-value { background-color: blue; /* プログレスバーの色を変更 */ border-radius: 10px; /* 角を丸く //必須 */ } progress.prog2[value]::-moz-progress-bar { background-color: blue; /* プログレスバーの色を変更 */ } </style> <script> let date,Year,Month,Week,Day,dayOfWeek,Hour,Min,Sec; let WeekItems = ["日", "月", "火", "水", "木", "金", "土"]; let MelodyProgValue = 0, max_Ix; //メロディ進捗度 let MelodytitleNum = 0; let tempAd; function Front0(num) { //1桁の場合、前ゼロ設定 let ret; if( num < 10 ) { ret = "0" + num; } else { ret = num; } return ret; } function ShowTimeStamp() { //タイムスタンプ表示 let msg1; date = new Date(); //インスタンス生成 Year = Front0(date.getFullYear()); //西暦年 //4桁 Month = Front0(date.getMonth() + 1); //月 Day = Front0(date.getDate()); //日 Week = date.getDay(); //曜日 //0,1,2,3,4,5,6, dayOfWeek = WeekItems[Week]; //日、月、火、水、木、金、土、 Hour = Front0( date.getHours() ); //時 Min = Front0( date.getMinutes() ); //分 Sec = Front0( date.getSeconds() ); //秒 msg1 = `${Year}年${Month}月${Day}日(${dayOfWeek}) ${Hour}:${Min}:${Sec}`; //テンプレートリテラル表記 //ECMAScript 6から使えるようになった構文 document.getElementById("TimeAreaId").innerHTML = msg1; } async function updateOutput(){ //Aruduino言語からデータ取得、outputタグの表示更新 const output = document.getElementById("output"); try { const response = await fetch("/get/mode"); if (response.ok)output.textContent = await response.text(); else { throw new Error(); } } catch (error) { console.log(error); } } async function updateOutput2(){ //Aruduino言語からデータ取得、outputタグの表示更新 const output2 = document.getElementById("output2"); try { const response2 = await fetch("/get/SongWords"); if (response2.ok)output2.textContent = await response2.text(); else { throw new Error(); } } catch (error) { console.log(error); } } function ShowLabel(){ //ラベル 演奏中/一時停止 の選択、表示 let Data, temp, ysMode, Ix, tempData; Data = Number(document.getElementById('output').textContent); //文字列データ --> 数値に変換 temp = Data /1000000; //百万以上の値を抽出 → PlayModeの値抽出 //一時停止/再開モード摘出 if(temp >= 1)ysMode = 1; //PlayMode = 1 else ysMode = 0; //PlayMode = 0 tempData = Data % 1000000; //百万未満の値を抽出  //メロディ進捗プログレスバー 現況進捗%演算 Ix = tempData / 10000; //1万以上の値を抽出 //音符の発音時間、無音時間のモード if(MelodytitleNum == 0)max_Ix = 44; else if(MelodytitleNum == 1)max_Ix = 51; else if(MelodytitleNum == 2)max_Ix = 31; else max_Ix = 0; MelodyProgValue = (Ix * 100)/ max_Ix; //メロディ進捗プログレスバー 現況進捗%演算 tempAd = tempData % 10000; //1万未満の値を抽出 //ADコンバータ変換値抽出 //一時停止/演奏中ラベル: 文字変更 & 背景色変更 let ysID1 = document.getElementById('1'); let ysID2 = document.getElementById('2'); if(ysMode == 0){ ysID1.style.backgroundColor = "yellowgreen"; ysID2.textContent = '一時停止'; ysID2.style.fontSize = '24px'; ysID2.style.fontWeight = 'bold'; }else{ ysID1.style.backgroundColor = "yellow"; ysID2.textContent = '演奏中'; ysID2.style.fontSize = '24px'; ysID2.style.fontWeight = 'bold'; } } function ShowSongWords(){ //曲名・歌詞 切り替え let MelodyTitle; let msg0; let msg2; let elem = document.getElementById("SlideShow"); msg0 = document.getElementById('output2').textContent; //文字列データ //ふるさと if(msg0 == "Usagi"){ MelodyTitle = "唱歌: ふるさと"; MelodytitleNum = 0; msg2 = "兎追いし彼の山"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_YamaKawaUsagi_401x201.jpg"; } else if(msg0 == "Kobuna") { MelodyTitle = "唱歌: ふるさと"; MelodytitleNum = 0; msg2 = "小鮒釣りし彼の川"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_SpringRiver_400x240.jpg"; } else if(msg0 == "Yumeha"){ MelodyTitle = "唱歌: ふるさと"; MelodytitleNum = 0; msg2 = "夢は今も巡りて"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_Miho_Fuj_372x240.jpg"; } else if(msg0 == "Wasure") { MelodyTitle = "唱歌: ふるさと"; MelodytitleNum = 0; msg2 = "忘れ難き故郷"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_Kikansha005_415x240.jpg"; } //鉄道唱歌 else if(msg0 == "Kiteki") { MelodyTitle = "唱歌: 鉄道唱歌"; MelodytitleNum = 1; msg2 = "汽笛一聲新橋を"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_Tetudo1_432x240.jpg"; } else if(msg0 == "Hayawaga") { MelodyTitle = "唱歌: 鉄道唱歌"; MelodytitleNum = 1; msg2 = "はや我汽車は離れたり"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_Tetudo2_411x240.jpg"; } else if(msg0 == "Atago") { MelodyTitle = "唱歌: 鉄道唱歌"; MelodytitleNum = 1; msg2 = "愛宕の山に入りのこる"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_Tetudo3_347x240.jpg"; } else if(msg0 == "Tukio") { MelodyTitle = "唱歌: 鉄道唱歌"; MelodytitleNum = 1; msg2 = "月を旅路の友として"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_Tetudo4B_240x352.jpg"; } //赤とんぼ else if(msg0 == "Yuuyake") { MelodyTitle = "唱歌: 赤とんぼ"; MelodytitleNum = 2; msg2 = "夕焼け小焼けの赤とんぼ"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_Akatombo1_401x240.jpg"; } else if(msg0 == "Owarete") { MelodyTitle = "唱歌: 赤とんぼ"; MelodytitleNum = 2; msg2 = "負われて見たのはいつの日か"; elem.src = "http://www.ys-labo.com/pc/2024/6/PictureData1/_Akatombo2_401x240.jpg"; } else msg2 = "         "; document.getElementById("TitleAreaId").innerHTML = MelodyTitle; document.getElementById("SongWordsAreaId").innerHTML = msg2; } function get_MelodyProg(){ //Melody進捗プログレスバー document.getElementById('prog1').value = MelodyProgValue; //document.getElementByIdメソッドで //prog1要素の値valueに直接アクセス let per = document.getElementById('status'); per.value = Math.round(document.getElementById('prog1').value); //四捨五入 } function get_VolumeProg(){ //Volume プログレスバー let Volt; let text1 = "・ 入力電圧:"; let text2 = "[V]"; let VolumeProgValue = 25; //入力電圧: 電圧値 & プログレスバー Volt = 3.3 * tempAd /4095; //n.toFixed(1); document.getElementById('AdValueAreaId').textContent = text1 + Volt.toFixed(2) + text2; VolumeProgValue = (tempAd * 100) / 4095; document.getElementById('prog2').value = VolumeProgValue; //document.getElementByIdメソッドで //prog1要素の値valueに直接アクセス } function ShowPage() //ブラウザのページを表示 { ShowTimeStamp(); //タイムスタンプ表示 updateOutput(); //PlayModeデータ取得 ShowLabel(); //演奏中/一時停止ラベル表示 updateOutput2(); ShowSongWords(); //歌詞の表示 get_MelodyProg(); //Melodyプログレスバー値設定/表示 get_VolumeProg(); //Volumeプログレスバー値設定/表示 } setInterval('ShowPage()', 100); //表示、100[msec]毎に更新 </script> </head> <body> <!--スマホ画面表示--> <div class = "top_block"> &emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; <h2 id="TimeAreaId" class="TimeStampFont">時刻表示部</h2> <h2>picoWによる<br> &emsp;スマホ式WiFi_STAモード型リモコン付<br> &emsp;&emsp;PWMメロディー発生器<br></h2> <h3>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; <a href="http://www.ys-labo.com/"><b style="color : blue;">YS電子工作デザイン</b></a> <hr> <div> <h1 id="TitleAreaId">&emsp;<b></b></h1> <h2 id="SongWordsAreaId">&emsp;<b></b></h2> <span><h2<b><progress id="prog1" class="prog1" max="100" min="0" value="0"></progress>:<output id = status>0</output>%</b></h2></span> <img id = "SlideShow" src = "http://www.ys-labo.com/pc/2024/6/PictureData1/YamaKawaUsagi_401x201.jpg"; height=240 vspace="5"> <div id = "1" class="Label"> <p id = "2" class="text_Label"></p> </div> <div> <table border="0"> <tbody> <tr> <td>&emsp;&emsp;&emsp;&emsp;<button type="button" class="buttonA" onclick="location.href='/myTouch'">Play/Pause</button></td> <td>&emsp;&emsp;&emsp;&emsp;<button type="button" class="buttonA" onclick="location.href='/mySkip'">Skip</button> </td> </tr> </tbody> </table> <p hidden id="output"></p> <!-- 非表示--> <p hidden id="output2"></p> <!-- 非表示--> </div> <hr> <参考> <br>・ 最新:<a href="https://www3.nhk.or.jp/news/"><b>NHKニュース</b></a></h3> <h3 id="AdValueAreaId">&emsp;<b></b></h3> <!-- 新しいプログレスバー --> &emsp;&emsp;&emsp;<progress id="prog2" class="prog2" max="100" min="0" value="0"></progress> </div> </body> </html> )"; void OnkaiOut(int doremi, float duty) //PWM出力 { analogWriteFreq(doremi); //周波数設定 analogWriteRange(1024); //分解能 10bit:1024 analogWrite(GpPwm,1024*duty); //PWM出力ピンに出力 } void ClosePWM(void) //PWM出力停止 { analogWriteFreq(100); //100Hz analogWriteRange(1024); //分解能 10bit:1024 analogWrite(GpPwm,0); //Duty = 0; } void SwCheck(){ //SW操作検出チェック //開始/一時停止SW if(digitalRead(GpPlayPauseSw) == 0)SwCount_PauseSw++; else SwCount_PauseSw = 0; if(SwCount_PauseSw == 20){ //チャタリング対策 if(PlayMode == 0)PlayMode = 1; else PlayMode = 0; } if(SwCount_PauseSw >= 21)SwCount_PauseSw = 21; //メロディ曲のスキップSW if(digitalRead(GpPlaySkipSw) == 0)SwCount_SkipSw++; else SwCount_SkipSw = 0; if(SwCount_SkipSw == 20){ //チャタリング対策 if(SkipMode == 0)SkipMode = 1; else SkipMode = 0; } if(SwCount_SkipSw >= 21)SwCount_SkipSw = 21; } void SkipMelody() //メロディー曲(スキップメカスイッチの場合) { if(SkipMode == 1) { SkipMode = 0; MelodyMode++; states = SET_SOUND_FREQUENCY_TIME; ix = 0; if(MelodyMode >= 3)MelodyMode = 0; } } void LedCont(){ //LED制御 if(PlayMode == 1){ //再生中 digitalWrite(GpLedRed, 1); //LED赤: 点灯 digitalWrite(GpLedGreen, 0); //LED緑: 消灯 } else{ //一時停止中 digitalWrite(GpLedRed, 0); //LED赤: 消灯 digitalWrite(GpLedGreen, 1); //LED緑: 点灯 ClosePWM(); //PWM出力停止 } } // サーバーリクエスト時処理関数 void handleRoot() { server.send(200, "text/html", html); //レスポンス200を返し、htmlデータ送信 } void TouchAndroid(){ //Android 画面 演奏/一時停止タッチ操作処理 if(PlayMode == 0)PlayMode = 1; else PlayMode = 0; handleRoot(); } void TouchSkipMelody(){ //メロディー曲スキップ(Android画面ボタンによるスキップの場合) PlayMode = 0; //演奏一時停止 MelodyMode++; //メロディー曲番号インクリメント states = SET_SOUND_FREQUENCY_TIME; //スキップ後の初期ステート設定 ix = 0; //スキップ後の初期要素番号設定 //{音階(音の周波数),音価(音が発生している時間),無音の時間)}  if(MelodyMode >= 3)MelodyMode = 0; //メロディー曲番号が最後の場合 → 最初のメロディ曲に戻る PlayMode = 1; //演奏再開 handleRoot(); } // ブラウザ表示更新:PlayMode //演奏/一時停止 void getMode(){ int SendData; char buf[32]; AdValue12 = analogRead(VOLUME_PIN); //可変抵抗器AD値を読み出し SendData = PlayMode * 1000000 //100万倍 ////PlayMode、ix、AdValue12データを加算した送信データを作成 + ix * 10000 //1万倍 + AdValue12; sprintf(buf, "%d", SendData); // dataの値を文字列として格納 server.send(200, "text/html", buf); // レスポンス200を返し、dataを文字列で送信 } // ブラウザ表示更新:歌詞更新 void getSongWords(){ char buf[32]; // data文字列格納バッファ char str_Usagi[] = "Usagi"; //兎追いし彼の山 char str_Kobuna[] = "Kobuna"; //小鮒釣りし彼の川 char str_Yumeha[] = "Yumeha"; //夢は今も巡りて char str_Wasure[] = "Wasure"; //忘れ難き故郷 char str_Kiteki[] = "Kiteki"; //汽笛一聲新橋を char str_Hayawaga[] = "Hayawaga"; //はや我汽車は離れたり char str_Atago[] = "Atago"; //愛宕の山に入りのこる char str_Tukiwo[] = "Tukio"; //月を旅路の友として char str_Yuuyake[] = "Yuuyake"; //夕焼け小焼けの 赤とんぼ char str_Owarete[] = "Owarete"; //負われて見たのは いつの日か char str_Space[] = " "; switch(MelodyMode){ case 0: //ふるさと if((ix >= 0) && (ix < 10))sprintf(buf, "%s", str_Usagi); else if(ix < 20)sprintf(buf, "%s", str_Kobuna); else if(ix < 35)sprintf(buf, "%s", str_Yumeha); else if(ix < 45)sprintf(buf, "%s", str_Wasure); else sprintf(buf, "%s", str_Space); break; case 1: //鉄道唱歌 if((ix >= 0) && (ix < 13))sprintf(buf, "%s", str_Kiteki); else if(ix < 26)sprintf(buf, "%s", str_Hayawaga); else if(ix < 39)sprintf(buf, "%s", str_Atago); else if(ix < 52)sprintf(buf, "%s", str_Tukiwo); else sprintf(buf, "%s", str_Space); break; case 2: //赤とんぼ if((ix >= 0) && (ix < 14))sprintf(buf, "%s", str_Yuuyake); else if(ix < 32)sprintf(buf, "%s", str_Owarete); else sprintf(buf, "%s", str_Space); break; default: break; } server.send(200, "text/html", buf); } void setup(void) { //UART開始 Serial.begin(115200); delay(50); // WiFi接続開始(STSモード) WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { //接続完了してなければ delay(500); Serial.print("."); } Serial.print("\nSSID: "); // SSID表示 Serial.println(WiFi.SSID()); Serial.print("IP: "); // IPアドレス表示 Serial.println(WiFi.localIP()); //192.168.43.98 server.on("/", handleRoot);//サーバー設定 server.on("/myTouch", TouchAndroid); //Android画面 Play/Pauseボタン操作 受信処理 //第1引き数の先頭に、"/"必須 //server.on("/#", Led); //<button type="button" class="example"><a href="#">Play/Pause</a></button> //上記の場合 "#"、"/#" いずれでもLed()内の内臓LEDは点灯しない→関数LED()へ制御は達していない server.on("/mySkip", TouchSkipMelody); server.on("/get/mode", getMode); // データ表示更新受信処理 server.on("/get/SongWords",getSongWords); // server.on("/get/AdCovert", getAdConvert); server.begin();//サーバーの起動 server.begin(); Serial.println("HTTP server started"); pinMode(GpPwm, OUTPUT); //PWM 出力モードに設定 pinMode(GpLedRed, OUTPUT); //LED  pinMode(GpLedGreen, OUTPUT); //LED pinMode(GpPlayPauseSw, INPUT_PULLUP); //プルアップ付き入力 pinMode(GpPlaySkipSw, INPUT_PULLUP); //プルアップ付き入力 analogReadResolution(12); //AD変換分解能12ビット pinMode(VOLUME_PIN, INPUT); //AD変換アナログ入力 states = SET_SOUND_FREQUENCY_TIME; //最初の音符解読ステート設定 MelodyMode = 0; } void loop(void) { server.handleClient(); //登録した情報に従ってクライアントからのリクエストを処理する関数 if(PlayMode == 1){ switch(MelodyMode){ case 0: switch(states){ case SET_SOUND_FREQUENCY_TIME: //音階周波数、及びPWM音発生時間設定 OnkaiOut(Furusato[ix][0],0.5); //PWM出力開始 Fursato[][3] interval_T = Furusato[ix][1] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //PWM終了時刻計算 states = CHECK_SOUNDING_TIME; break; case CHECK_SOUNDING_TIME: //PWM音終了時刻チェック if(target_T <= time_us_64()) states = STOP_SOUNDING; break; case STOP_SOUNDING: //PWM音終了・無音処理 //ショート無音時間設定 analogWrite(GpPwm,0); //PWM 停止 //必須 interval_T = 50 * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //ショート無音時間終了時刻計算 states = CHECH_SHORT_SILENT_TIME; break; case CHECH_SHORT_SILENT_TIME: //ショート無音時間終了チェック if(target_T <= time_us_64()) states = STOP_SHORT_SILENT_TIME; break; case STOP_SHORT_SILENT_TIME: //音符上の休止無音時間、メロディー終了後の無音時間設定 interval_T = Furusato[ix][2] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //無音終了時刻計算 states = CHECK_SILENT_TIME; break; case CHECK_SILENT_TIME: //音符上の休止無音時間チェック if(target_T <= time_us_64()) { ix++; if(Furusato[ix][0] == -1) { MelodyMode++; states = SET_SOUND_FREQUENCY_TIME; if(MelodyMode >= 3)MelodyMode = 0; ix = 0; //曲の終末を検出 → 曲の先頭から繰り返す } states = SET_SOUND_FREQUENCY_TIME; //初めに戻る } break; default: break; } break; case 1: switch(states){ case SET_SOUND_FREQUENCY_TIME: //音階周波数、及びPWM音発生時間設定 OnkaiOut(TetsudoShoka[ix][0],0.5); //PWM出力開始 Fursato[][3] interval_T = TetsudoShoka[ix][1] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //PWM終了時刻計算 states = CHECK_SOUNDING_TIME; break; case CHECK_SOUNDING_TIME: //PWM音終了時刻チェック if(target_T <= time_us_64()) states = STOP_SOUNDING; break; case STOP_SOUNDING: //PWM音終了・無音処理 //ショート無音時間設定 analogWrite(GpPwm,0); //PWM 停止 //必須 interval_T = 50 * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //ショート無音時間終了時刻計算 states = CHECH_SHORT_SILENT_TIME; break; case CHECH_SHORT_SILENT_TIME: //ショート無音時間終了チェック if(target_T <= time_us_64()) states = STOP_SHORT_SILENT_TIME; break; case STOP_SHORT_SILENT_TIME: //音符上の休止無音時間、メロディー終了後の無音時間設定 interval_T = TetsudoShoka[ix][2] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //無音終了時刻計算 states = CHECK_SILENT_TIME; break; case CHECK_SILENT_TIME: //音符上の休止無音時間チェック if(target_T <= time_us_64()) { ix++; if(TetsudoShoka[ix][0] == -1) { MelodyMode++; states = SET_SOUND_FREQUENCY_TIME; if(MelodyMode >= 3)MelodyMode = 0; ix = 0; //曲の終末を検出 → 曲の先頭から繰り返す } states = SET_SOUND_FREQUENCY_TIME; //初めに戻る } break; default: break; } break; case 2: switch(states){ case SET_SOUND_FREQUENCY_TIME: //音階周波数、及びPWM音発生時間設定 OnkaiOut(Akatonbo[ix][0],0.5); //PWM出力開始 Fursato[][3] interval_T = Akatonbo[ix][1] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //PWM終了時刻計算 states = CHECK_SOUNDING_TIME; break; case CHECK_SOUNDING_TIME: //PWM音終了時刻チェック if(target_T <= time_us_64()) states = STOP_SOUNDING; break; case STOP_SOUNDING: //PWM音終了・無音処理 //ショート無音時間設定 analogWrite(GpPwm,0); //PWM 停止 //必須 interval_T = 50 * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //ショート無音時間終了時刻計算 states = CHECH_SHORT_SILENT_TIME; break; case CHECH_SHORT_SILENT_TIME: //ショート無音時間終了チェック if(target_T <= time_us_64()) states = STOP_SHORT_SILENT_TIME; break; case STOP_SHORT_SILENT_TIME: //音符上の休止無音時間、メロディー終了後の無音時間設定 interval_T = Akatonbo[ix][2] * 1000; current_T = time_us_64(); //pico起動後経過の時間取得[μsec] target_T = current_T + interval_T; //無音終了時刻計算 states = CHECK_SILENT_TIME; break; case CHECK_SILENT_TIME: //音符上の休止無音時間チェック if(target_T <= time_us_64()) { ix++; if(Akatonbo[ix][0] == -1) { MelodyMode++; states = SET_SOUND_FREQUENCY_TIME; if(MelodyMode >= 3)MelodyMode = 0; ix = 0; //曲の終末を検出 → 曲の先頭から繰り返す } states = SET_SOUND_FREQUENCY_TIME; //初めに戻る } break; default: break; } break; default: break; } } //if(PlayMode == 1) SwCheck(); //ボタンスイッチチック SkipMelody(); //メロディをスキップ LedCont(); //LEDの点灯/消灯制御実施 }